﻿Imports System.Threading
Imports System.Reflection
Imports System.Text
Imports Microsoft.Win32
Imports System.Net
Imports System.IO

Public Class frm_main

    Private _tools As New Tools
    Private _download_running As Boolean
    Private _dic_download_speed As New Dictionary(Of String, Integer)
    Private _dic_download_size As New Dictionary(Of String, Long)
    Private _new_version_available As Boolean = False
    Private _close_application As Boolean = False
    Private _full_download_size As Long = 0
    Private _download_bytes_loaded As Long = 0
    Private _max_download_speed As Integer
    Private _list_files_to_unrar As New List(Of UnRARInfo)
    Private _count_active_unrar_threads As Integer = 0
    Private _current_download_speed As Long = 0
    Private _remaining_download_time As String
    Private _stopwatch As New Stopwatch
    Private _synclock_progress_bar As New Object
    Private _synclock_progress_time_remaining As New Object

    Private _post_download_shell_cmd As String
    Private _post_download_sound_file As String

    'Debug
    Private _debug_sw As StreamWriter
    Private _debug_listener As TextWriterTraceListener
    Private _debug_enabled As Boolean = False


    Private Shared _current_sfdl_file As New SFDL_File
    Private Shared _current_sfdl_file_path As String
    Private Shared _settings As Settings
    Private Shared _max_dl_speed_achieved As Integer
    Private Shared _elapsed_download_time As Long

    Public Shared _thread_handler As New ThreadHandler

    Public Event MaxDownloadSpeedChanged(ByVal _value As Integer)


#Region "Properties"

    Public ReadOnly Property GetSettings As Settings
        Get
            Return _settings
        End Get
    End Property

    Public ReadOnly Property GetActiveThreadCount As Integer
        Get
            Return _thread_handler.GetActiveThreadCount
        End Get
    End Property

    Public ReadOnly Property GetDownloadSpeed As Long
        Get
            Return _current_download_speed
        End Get
    End Property

    Public WriteOnly Property SetFullDownloadSize As Long
        Set(value As Long)
            _full_download_size = value
        End Set
    End Property

    Public ReadOnly Property GetFullDownloadSize As Long
        Get
            Return _full_download_size
        End Get
    End Property

    Public Property GetSetBytesDownloaded As Long
        Set(value As Long)
            _download_bytes_loaded = value
        End Set
        Get
            Return _download_bytes_loaded
        End Get
    End Property

    Public ReadOnly Property GetSFDLMaxThreads As Integer
        Get
            Return _current_sfdl_file.GetSetMaxDownloadThread
        End Get
    End Property

    Public Property GetSetCurrentSFDLFile As SFDL_File
        Set(value As SFDL_File)
            _current_sfdl_file = value
        End Set
        Get
            Return _current_sfdl_file
        End Get
    End Property

    Public Property GetSetCurrentSFDLFilePath As String
        Set(value As String)
            _current_sfdl_file_path = value
        End Set
        Get
            Return _current_sfdl_file_path
        End Get
    End Property

    Public Property GetSetMaxDownloadSpeedAchieved As Integer
        Set(value As Integer)
            _max_dl_speed_achieved = value
        End Set
        Get
            Return _max_dl_speed_achieved
        End Get
    End Property

    Public Property GetSetElapsedDownloadTime As Long
        Set(value As Long)
            _elapsed_download_time = value
        End Set
        Get
            Return _elapsed_download_time
        End Get
    End Property

#End Region

#Region "Invokes"

    Private Sub InsertSFDLControls(ByVal _value() As Control)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.InsertSFDLControls(_value))
        Else
            MainLayoutPanel.Controls.AddRange(_value)
        End If
    End Sub

    Private Sub UpdateStatusActionLabelText(ByVal _value As String)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusActionLabelText(_value))
        Else
            StatusLabel_Current_Action.Text = _value
        End If
    End Sub

    Private Sub UpdateStatusSpeedText(ByVal _value As Integer)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusSpeedText(_value))
        Else
            StatusLabel_CurrentSpeed.Text = String.Format("{0} KB/s", _value.ToString)
        End If
    End Sub

    Private Sub UpdateStatusActionLabelImage(ByVal _value As Image)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusActionLabelImage(_value))
        Else
            StatusLabel_Current_Action.Image = _value
        End If
    End Sub

    Private Sub UpdateStatusProgressBarMaximum(ByVal _value As Long)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusProgressBarMaximum(_value))
        Else
            StatusProgressBar.Maximum = CInt(StatusProgressBar.Maximum + _value)
        End If
    End Sub

    Private Sub UpdateStatusProgressBarValue(ByVal _value As Long, ByVal _filename As String, ByVal _reset_counter As Boolean)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusProgressBarValue(_value, _filename, _reset_counter))
        Else

            Dim _old_value As Long = 0

            SyncLock _synclock_progress_bar

                GetSetBytesDownloaded = 0

                If _dic_download_size.ContainsKey(_filename) = False Then
                    _dic_download_size.Add(_filename, _value)
                Else

                    _old_value = _dic_download_size.Item(_filename)

                    _dic_download_size.Remove(_filename)

                    If _reset_counter = False Then
                        _dic_download_size.Add(_filename, _old_value + _value)
                    Else
                        _dic_download_size.Add(_filename, _value)
                    End If

                End If

                For Each _item In _dic_download_size
                    GetSetBytesDownloaded = GetSetBytesDownloaded + _item.Value
                Next

                StatusProgressBar.Value = CInt((GetSetBytesDownloaded / GetFullDownloadSize) * 100)

            End SyncLock


        End If
    End Sub

    Private Sub UpdateStatusProgressBarPercentValue(ByVal _value As Integer)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusProgressBarPercentValue(_value))
        Else
            StatusProgressBar.Value = _value
        End If
    End Sub

    Private Sub UpdateStatusSpeedAndReaminingTime(ByVal _value As Long, ByVal _filename As String)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UpdateStatusSpeedAndReaminingTime(_value, _filename))
        Else

            Dim _full_speed As Integer = 0
            Dim _time_remaining As Double = 0

            SyncLock _synclock_progress_time_remaining

                If _dic_download_speed.ContainsKey(_filename) = False Then
                    _dic_download_speed.Add(_filename, CInt(_value))
                Else
                    _dic_download_speed.Remove(_filename)
                    _dic_download_speed.Add(_filename, CInt(_value))
                End If

                For Each _item In _dic_download_speed

                    _full_speed += _item.Value
                Next

                StatusLabel_CurrentSpeed.Text = String.Format("{0} KB/s", _full_speed)

                If GetSetMaxDownloadSpeedAchieved < _full_speed Then
                    GetSetMaxDownloadSpeedAchieved = _full_speed
                End If

                _current_download_speed = _full_speed

                If Not _full_speed = 0 Then

                    Dim _size_remaining As Double = 0

                    _size_remaining = GetFullDownloadSize - GetSetBytesDownloaded

                    _time_remaining = Math.Round(Double.Parse(CStr(((_size_remaining / 1024) / _full_speed) / 60)), 2)

                    StatusLabel_TimeRemaining.Text = "Verbleibende Zeit: " & _tools.ConvertDecimal2Time(_time_remaining).ToString
                    _remaining_download_time = _tools.ConvertDecimal2Time(_time_remaining).ToString

                End If

            End SyncLock

        End If
    End Sub

    Private Sub UnLockGUI_Downloading()
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UnLockGUI_Downloading())
        Else
            StatusLabel_TimeRemaining.Visible = False
            cmd_start_download.Enabled = True
            chk_Panel_Header.Enabled = True
            cmd_stop_download.Enabled = False
        End If
    End Sub

    Private Sub LockGUI_Downloading()
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UnLockGUI_Downloading())
        Else
            StatusLabel_TimeRemaining.Visible = True
            cmd_start_download.Enabled = False
            cmd_stop_download.Enabled = True
            chk_Panel_Header.Enabled = False
        End If
    End Sub

    Private Sub LockGUI_SearchUpdates()
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.LockGUI_SearchUpdates())
        Else
            Me.Enabled = False
        End If
    End Sub


    Private Sub UnLockGUI_SearchUpdates()
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.UnLockGUI_SearchUpdates())
        Else
            Me.Enabled = True
        End If
    End Sub

    Private Sub CloseApp()
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.CloseApp())
        Else
            Me.Close()
        End If
    End Sub

    Private Sub RunUnRARWorker(ByVal _value As Object)
        If Me.InvokeRequired Then
            Me.Invoke(Sub() Me.RunUnRARWorker(_value))
        Else
            bgw_unrar.RunWorkerAsync(_value)
        End If
    End Sub
#End Region

#Region "Hilf-Subs"

    Sub CloseApplication()

        _close_application = True

        If _download_running = True Then

            If MessageBox.Show("Es läuft noch ein Download!" & vbNewLine & "Downloads stoppen und Program beenden?", "Achtung", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) = Windows.Forms.DialogResult.Yes Then

                cmd_stop_download.Enabled = False

                StatusLabel_Current_Action.Text = "Stoppe Download..."

                _thread_handler.SetDownloadStopped = True

                For Each _item In MainLayoutPanel.Controls

                    If _item.GetType() Is GetType(ctrFTPClient) Then

                        Dim _control As New ctrFTPClient

                        _control = _item

                        Dim _stop_thread As New Thread(AddressOf _control.StopDownload)

                        _stop_thread.Start()

                    End If

                Next
            Else

                _close_application = False

            End If

        Else

            If MessageBox.Show("Wollen Sie das Programm wirklich beenden?", "SFDL.NET", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
                Application.Exit()
            Else
                _close_application = False
            End If

        End If

    End Sub


#End Region

#Region "Update Check"

    Private Sub bgw_check_updates_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgw_check_updates.DoWork

        Dim _client_version As String
        Dim _server_version As String
        Dim _tmp_version_file As String
        Dim _tmp_split_server() As String
        Dim _tmp_split_client() As String

        _tmp_version_file = IO.Path.Combine(Application.StartupPath, "version_sfdl.net.tmp")

        _client_version = Assembly.GetExecutingAssembly.GetName.Version.ToString

        Try

            If My.Computer.Network.IsAvailable Then

                If IO.File.Exists(_tmp_version_file) Then
                    IO.File.Delete(_tmp_version_file)
                End If

                My.Computer.Network.DownloadFile("https://sfdl.svn.codeplex.com/svn/SFDL.NET/UpdateCheck/version", _tmp_version_file)

                _server_version = My.Computer.FileSystem.ReadAllText(_tmp_version_file).Trim.ToString

                _tmp_split_server = _server_version.Split(CChar("."))
                _tmp_split_client = _client_version.Split(CChar("."))

                For x = 0 To _tmp_split_server.Length - 1

                    Dim _int_server As Integer = 0
                    Dim _int_client As Integer = 0

                    _int_server = Integer.Parse(_tmp_split_server(x).ToString)
                    _int_client = Integer.Parse(_tmp_split_client(x).ToString)

                    If _int_server > _int_client Then
                        _new_version_available = True
                    End If

                Next

                IO.File.Delete(_tmp_version_file)

            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Fehler beim UpdateCheck!", MessageBoxButtons.OK, MessageBoxIcon.Warning)
        End Try

    End Sub

    Private Sub bgw_check_updates_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw_check_updates.RunWorkerCompleted

        StatusLabel_Current_Action.Text = "Bereit"
        StatusLabel_Current_Action.Image = My.Resources.DownloadOK

        UnLockGUI_SearchUpdates()

        If _new_version_available Then
            frm_new_update.ShowDialog()
        Else
            StatusLabel_Current_Action.Text = "Kein Update vorhanden!"
        End If

    End Sub

    Private Sub UpdateCheckToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles UpdateCheckToolStripMenuItem.Click
        StatusLabel_Current_Action.Text = "Prüfe auf Updates..."
        StatusLabel_Current_Action.Image = My.Resources.UpdateCheck
        bgw_check_updates.RunWorkerAsync()
    End Sub

#End Region

#Region "EventHandler"


    Private Sub ControlDownloadFinished(ByVal _control As ctrFTPClient, ByVal _failed As Boolean)


        RemoveHandler _control.DownloadFinished, AddressOf ControlDownloadFinished
        RemoveHandler _control.UpdateStatusProgressBarValue, AddressOf ControlUpdateProgressBarValue
        RemoveHandler _control.UpdateStatusSpeed, AddressOf ControlUpdateDownloadSpeed

        If _close_application = False Then

            RaiseEvent MaxDownloadSpeedChanged(_tools.CalculateMaxDownloadSpeed(GetSFDLMaxThreads, GetActiveThreadCount, txt_max_dl_speed.Text))

            Try


                If _control.DownloadStoppped = False And String.IsNullOrEmpty(_control.GetLocalFilePath) = False Then

                    If _settings.GetSetUnRARAfterDownload And _tools.isFileArchive(_control.GetLocalFilePath) Then

                        Dim _unrar_info As New UnRARInfo

                        _unrar_info.GetSetFile = _control.GetLocalFilePath
                        _unrar_info.GetSetPassword = String.Empty

                        _list_files_to_unrar.Add(_unrar_info)

                    End If

                Else
                    _list_files_to_unrar.Clear()
                End If

                _thread_handler.DecrementActiveThreadCount()

                If Me.GetActiveThreadCount = 0 And _download_running = True Then

                    _download_running = False

                    _stopwatch.Stop()
                    GetSetElapsedDownloadTime = _stopwatch.ElapsedMilliseconds

                    If _settings.GetSetUnRARAfterDownload And _list_files_to_unrar.Count >= 1 Then
                        UpdateStatusActionLabelText("Suche nach Passwort zum Entpacken...")
                        UpdateStatusActionLabelImage(My.Resources.compress)
                        RunUnRARWorker(_list_files_to_unrar)

                    Else

                        UnLockGUI_Downloading()

                        UpdateStatusActionLabelText("Bereit")
                        UpdateStatusActionLabelImage(My.Resources.DownloadOK)
                        UpdateStatusSpeedText(0)

                        PostDownloadAction()

                    End If

                End If

            Catch ex As Exception

            End Try

        End If

    End Sub
    Private Sub ControlUpdateProgressBarValue(_value As Long, ByVal _filename As String, ByVal _reset_counter As Boolean)
        UpdateStatusProgressBarValue(_value, _filename, _reset_counter)
    End Sub

    Private Sub ControlUpdateDownloadSpeed(_value As Integer, _filename As String)
        UpdateStatusSpeedAndReaminingTime(_value, _filename)
    End Sub

    Private Sub frm_setting_settings_update_event(_new_settings As Settings)
        _settings = _new_settings
    End Sub

#End Region

#Region "Stop Download"

    Private Sub bgw_stop_downloads_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs)
        cmd_stop_download.Enabled = True
    End Sub

    Private Sub cmd_stop_download_Click(sender As Object, e As EventArgs) Handles cmd_stop_download.Click

        Dim _control_list As New List(Of ctrFTPClient)

        Try

            If _download_running = False Then
                Throw New Exception("Es läuft kein Download!")
            End If

            cmd_stop_download.Enabled = False

            StatusLabel_Current_Action.Text = "Stoppe Download..."

            _thread_handler.SetDownloadStopped = True

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    Dim _stop_thread As New Thread(AddressOf _control.StopDownload)

                    _stop_thread.Start()

                End If

            Next

            _stopwatch.Stop()

            GetSetElapsedDownloadTime = _stopwatch.ElapsedMilliseconds

            MemoryManagement.FlushMemory()

        Catch ex As Exception
            MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try

    End Sub

#End Region

#Region "UnRAR"

    Private Sub ArchivEntpackenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ArchivEntpackenToolStripMenuItem.Click

        If Not OFD_Extract.ShowDialog = Windows.Forms.DialogResult.Cancel Then

            Dim _unrar_info As New UnRARInfo
            Dim _list As New List(Of UnRARInfo)

            _unrar_info.GetSetFile = OFD_Extract.FileName
            _unrar_info.GetSetPassword = String.Empty

            _list.Add(_unrar_info)

            UpdateStatusActionLabelText("Suche nach Passwort zum Entpacken...")
            UpdateStatusActionLabelImage(My.Resources.compress)

            bgw_unrar.RunWorkerAsync(_list)


        End If
    End Sub

    Private Sub bgw_unrar_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgw_unrar.DoWork

        Dim _list_unrar_info As New List(Of UnRARInfo)
        Dim _unrar As SevenZip.SevenZipExtractor
        Dim _tmp_list As New List(Of String)


        _list_unrar_info = CType(e.Argument, Global.System.Collections.Generic.List(Of Global.SFDL.NET.UnRARInfo))

        If _tools.isx64 Then
            SevenZip.SevenZipExtractor.SetLibraryPath(IO.Path.Combine(Application.StartupPath, "7z64.dll"))
        Else
            SevenZip.SevenZipExtractor.SetLibraryPath(IO.Path.Combine(Application.StartupPath, "7z.dll"))
        End If

        For Each _unrar_info As UnRARInfo In _list_unrar_info

            Try

                _unrar = New SevenZip.SevenZipExtractor(_unrar_info.GetSetFile)
                _tmp_list = New List(Of String)

                'Versuche zu entpacken ohne Kennwort

                If _unrar.ArchiveFileData(0).Encrypted = False Then

                    If _unrar.Check = True Then
                        _unrar_info.GetSetPassword = String.Empty
                        _unrar_info.GetSetFile = _unrar_info.GetSetFile
                        _unrar_info.GetSetPasswordFound = True

                        For Each _vol_file In _unrar.VolumeFileNames
                            _tmp_list.Add(_vol_file)
                        Next

                        _unrar_info.GetSetVolumeFiles = _tmp_list

                    End If

                End If

                If GetSettings.GetSetUseUnRARPasswordList And _unrar_info.GetSetPasswordFound = False Then

                    For Each _password In _settings.GetSetUnRARPasswordList

                        _unrar = New SevenZip.SevenZipExtractor(_unrar_info.GetSetFile, _password)
                        _tmp_list = New List(Of String)

                        If _unrar.Check() = True Then
                            'pw passt
                            _unrar_info.GetSetPassword = _password
                            _unrar_info.GetSetFile = _unrar_info.GetSetFile
                            _unrar_info.GetSetPasswordFound = True

                            For Each _vol_file In _unrar.VolumeFileNames
                                _tmp_list.Add(_vol_file)
                            Next

                            _unrar_info.GetSetVolumeFiles = _tmp_list

                        End If

                    Next

                End If

                System.Threading.Thread.Sleep(3)
                _unrar.Dispose()

            Catch ex As Exception
            End Try

        Next

        bgw_unrar.ReportProgress(0, _list_unrar_info)


    End Sub

    Private Sub bgw_unrar_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw_unrar.ProgressChanged

        Dim _unrar_info_list As New List(Of UnRARInfo)

        _unrar_info_list = CType(e.UserState, Global.System.Collections.Generic.List(Of Global.SFDL.NET.UnRARInfo))

        _count_active_unrar_threads = 0

        For Each _unrar_info As UnRARInfo In _unrar_info_list

            Dim _unrar As SevenZip.SevenZipExtractor

            If _unrar_info.GetSetPasswordFound = True Then

                If String.IsNullOrEmpty(_unrar_info.GetSetPassword) Then
                    _unrar = New SevenZip.SevenZipExtractor(_unrar_info.GetSetFile)
                Else
                    _unrar = New SevenZip.SevenZipExtractor(_unrar_info.GetSetFile, _unrar_info.GetSetPassword)
                End If

                AddHandler _unrar.Extracting, AddressOf _unrar_progress
                AddHandler _unrar.ExtractionFinished, AddressOf _unrar_complete
                AddHandler _unrar.FileExists, AddressOf _unrar_file_exist

                UpdateStatusActionLabelText("Entpacke...")
                UpdateStatusProgressBarPercentValue(0)

                _count_active_unrar_threads += 1

                _unrar.BeginExtractArchive(IO.Path.GetDirectoryName(_unrar_info.GetSetFile))

            End If

        Next


    End Sub


    Private Sub bgw_unrar_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw_unrar.RunWorkerCompleted

        If _count_active_unrar_threads = 0 Then

            UnLockGUI_Downloading()
            UpdateStatusActionLabelText("Kein Passwort gefunden!")
            UpdateStatusActionLabelImage(My.Resources.DownloadFail)
            UpdateStatusSpeedText(0)

            PostDownloadAction()

        End If

    End Sub


    Private Sub _unrar_progress(sender As Object, e As SevenZip.ProgressEventArgs)

        UpdateStatusProgressBarPercentValue(e.PercentDone)

    End Sub

    Private Sub _unrar_complete(sender As Object, e As EventArgs)


        If GetSettings.GetSetDeleteAfterUnRAR Then

            Dim _unrar As SevenZip.SevenZipExtractor

            Dim _current_vol_files As New List(Of String)

            _unrar = CType(sender, SevenZip.SevenZipExtractor)

            For Each _vol In _unrar.VolumeFileNames
                _current_vol_files.Add(_vol)
            Next

            _unrar.Dispose()

            UpdateStatusActionLabelText("Lösche RAR Dateien...")

            For Each _file In _current_vol_files

                Try

                    If IO.File.Exists(_file) And _current_vol_files.Contains(_file) Then
                        IO.File.Delete(_file)
                    End If

                Catch ex As Exception
                    'Fehler beim löschen
                End Try

            Next

        End If

        _count_active_unrar_threads -= 1

        If _count_active_unrar_threads = 0 Then

            UnLockGUI_Downloading()
            UpdateStatusActionLabelText("Bereit")
            UpdateStatusActionLabelImage(My.Resources.DownloadOK)
            UpdateStatusSpeedText(0)

            PostDownloadAction()

        End If



    End Sub

    Private Sub _unrar_file_exist(sender As Object, e As SevenZip.FileOverwriteEventArgs)

        If MessageBox.Show(e.FileName & " existiert bereits. Überschreiben?", "Habe eine Frage", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
            IO.File.Delete(e.FileName)
        Else
            e.Cancel = True
        End If

    End Sub


#End Region

#Region "DragnDrop"

    Private Sub MainLayoutPanel_DragEnter(sender As Object, e As DragEventArgs) Handles MainLayoutPanel.DragEnter

        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            e.Effect = DragDropEffects.Copy
        End If

    End Sub

    Private Sub MainLayoutPanel_DragDrop(sender As Object, e As DragEventArgs) Handles MainLayoutPanel.DragDrop

        Dim _sfdl_file_path As String = String.Empty
        Dim _files() As String

        Try

            _files = CType(e.Data.GetData(DataFormats.FileDrop), String())

            If Not _files.Length = 0 Then
                _sfdl_file_path = _files(0).ToString
            End If

            If IO.Path.GetExtension(_sfdl_file_path).ToLower = ".sfdl" Then
                _tools.OpenSFDLFile(_sfdl_file_path)
            End If


        Catch ex As Exception
            MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try


    End Sub


#End Region

#Region "frm_main Events"

    Private Sub frm_main_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        If _close_application = False Then
            CloseApplication()
            If _close_application = False Then
                e.Cancel = True
            End If
        End If
    End Sub

    Private Sub frm_main_Load(sender As Object, e As EventArgs) Handles MyBase.Load


        Dim _settings_file_path As String = String.Empty

        If _tools.isLinux = False Then

            _settings_file_path = IO.Path.Combine(Environment.GetEnvironmentVariable("appdata"), "SFDL.NET")

            If IO.Directory.Exists(_settings_file_path) = False Then
                IO.Directory.CreateDirectory(_settings_file_path)
            End If

            _settings_file_path = IO.Path.Combine(Environment.GetEnvironmentVariable("appdata"), "SFDL.NET\settings.xml")

        Else
            _settings_file_path = (IO.Path.Combine(Application.StartupPath, "settings.xml"))
        End If

        _settings = New Settings


        'Load Settings
        If IO.File.Exists(_settings_file_path) Then

            _settings = CType(_tools.XMLDeSerialize(_settings, _settings_file_path), Settings)

            If _settings.GetSetExistingFileHandling = FTP.FTP.FileAction.None Then
                _settings.GetSetExistingFileHandling = FTP.FTP.FileAction.ResumeOrCreate
            End If

        Else

            'Load Default Settings

            _settings.GetSetDownloadDirectory = IO.Path.Combine(Application.StartupPath, "Download")

            If IO.Directory.Exists(IO.Path.Combine(Application.StartupPath, "Download")) = False Then
                IO.Directory.CreateDirectory(IO.Path.Combine(Application.StartupPath, "Download"))
            End If

            _settings.GetSetExistingFileHandling = FTP.FTP.FileAction.ResumeOrCreate
            _settings.GetSetUpdateCheck = True
            _settings.GetSetClicknLoad = True
            _settings.GetSetSend2Tray = True
            _settings.GetSetMaxDownloadThreads = 3
            _settings.GetSetUnRARAfterDownload = True

            _settings.GetSetShowSpeedreportAfterDownload = True
            _settings.GetSetSpeedreportTemplate = My.Settings.Default_Speedreport


            'Save Default Settings

            _tools.XMLSerialize(_settings, _settings_file_path)

        End If

        If _tools.isLinux = True Then

            _settings.GetSetUpdateCheck = False
            _settings.GetSetClicknLoad = False
            _settings.GetSetSend2Tray = False

        End If

        If _tools.isLinux = False Then

            'Try to register sfdl extension

            Try

                Dim _file_assoiciation As New FileAssociation

                _file_assoiciation.Extension = "sfdl"
                _file_assoiciation.ContentType = "application/sfdl.net"
                _file_assoiciation.FullName = "SFDL.NET Files"
                _file_assoiciation.IconIndex = 0
                _file_assoiciation.IconPath = IO.Path.Combine(Application.StartupPath, "Icon.ico")
                _file_assoiciation.ProperName = "SFDL.NET File"
                _file_assoiciation.AddCommand("open", Application.ExecutablePath.ToString & " " & Chr(34) & "%1" & Chr(34))

                _file_assoiciation.Create()

                If _settings.GetSetClicknLoad Then
                    _tools.RegisterSFDLURIHandler(Application.ExecutablePath)
                End If


            Catch ex As Exception

            End Try

        End If

        'Wenn SFDL File als Argument - > SFDL File öffnen

        If My.Application.CommandLineArgs.Count >= 1 Then

            Dim _file As String = String.Empty

            _file = My.Application.CommandLineArgs(0)

            If _file.StartsWith("sfdl://") Then

                _file = _file.Replace("sfdl://", "")

                If _file.StartsWith("http://") Or _file.StartsWith("www.") Then



                    If _file.StartsWith("http://www.xup.in") Then

                        Dim _cln_xup As New CnL_xup

                        _file = _cln_xup.DownloadFile(_file)
                    Else
                        _file = _tools.DownloadFile(_file)
                    End If



                End If

            End If

            If IO.File.Exists(_file) Then
                _tools.OpenSFDLFile(_file)
            End If

        End If

        'Funktionen auslassen welche unter Linux evtl. zu einem Fehler führen würden.

        If _tools.isLinux = False And _settings.GetSetPreventStandby = True Then

            _tools.No_Sleep()

        End If

        'Deaktivieren da auf Linux momentan nicht möglich
        If _tools.isLinux Then
            PostDownload_ShutdownPC.Enabled = False
            PostDownload_ShellExecute.Enabled = False
        End If

        'Auf Updates prüfen

        If _settings.GetSetUpdateCheck = True Then
            LockGUI_SearchUpdates()
            StatusLabel_Current_Action.Text = "Prüfe auf Updates..."
            StatusLabel_Current_Action.Image = My.Resources.UpdateCheck
            bgw_check_updates.RunWorkerAsync()
        Else
            StatusLabel_Current_Action.Text = "Bereit"
            StatusLabel_Current_Action.Image = My.Resources.DownloadOK
        End If




    End Sub

#End Region

#Region "MainToolStrip Button Events"

    Private Sub BeendenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles BeendenToolStripMenuItem.Click
        Me.Close()
    End Sub

    Private Sub ÖffnenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ÖffnenToolStripMenuItem.Click

        Dim _sfdl_file As New SFDL_File
        Dim _tools As New Tools

        'SFDL File öffnen & einlesen

        Try

            If Not OFD_SFDL_File.ShowDialog = Windows.Forms.DialogResult.Cancel Then
                _tools.OpenSFDLFile(OFD_SFDL_File.FileName)
            End If



        Catch ex As Exception
            MessageBox.Show("Es ist ein Fehler beim öffnen der Datei aufgetreten!", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

    End Sub

    Private Sub cmd_start_download_Click(sender As Object, e As EventArgs) Handles cmd_start_download.Click

        Try
            'Download starten

            Dim _counter As Integer = 0
            Dim _list As New List(Of Control)

            'Prüfen ob überhaupt eine Datei geöffnet ist und kein Download läuft

            If MainLayoutPanel.Controls.Count = 0 Then
                Throw New Exception("Du musst zuerst eine Datei öffnen!")
            End If

            If _download_running = True Then
                Throw New Exception("Der Download läuft bereits!")
            End If

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    If _control.chkActivate.Checked = True Then
                        _counter += 1
                    End If

                End If

            Next

            'Prüfen ob eine Datei zum herunterladen ausgewählt wurde

            If _counter = 0 Then
                Throw New Exception("Du musst mind. eine Datei zum Download auswählen!")
            End If

            LockGUI_Downloading()
            _download_running = True
            StatusProgressBar.Value = 0
            StatusProgressBar.Maximum = 100
            GetSetBytesDownloaded = 0
            SetFullDownloadSize = 0
            _list_files_to_unrar.Clear()
            _dic_download_speed.Clear()
            _dic_download_size.Clear()

            'Stoppuhr initialisieren
            _stopwatch.Start()


            _thread_handler = New ThreadHandler

            RaiseEvent MaxDownloadSpeedChanged(_tools.CalculateMaxDownloadSpeed(GetSFDLMaxThreads, _counter, txt_max_dl_speed.Text))

            StatusLabel_Current_Action.Text = "Downloading..."
            StatusLabel_Current_Action.Image = My.Resources.Downloading

            'Jedes aktivierte Control durchgehen und dem ThreadHandler übergeben

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    _control.pb_status.Image = Nothing
                    _control.lbl_dl_speed_status.Text = "0 KB/s"
                    _control.DownloadStoppped = False
                    _control.ProgBarStatus.Value = 0

                    If _control.chkActivate.Checked Then

                        Dim _download_thread As New Thread(AddressOf _control.Download)

                        AddHandler _control.DownloadFinished, AddressOf ControlDownloadFinished
                        AddHandler _control.UpdateStatusProgressBarValue, AddressOf ControlUpdateProgressBarValue
                        AddHandler _control.UpdateStatusSpeed, AddressOf ControlUpdateDownloadSpeed

                        _control.pb_status.Image = Nothing
                        _control.lbl_dl_speed_status.Text = "0 KB/s"
                        _control.DownloadStoppped = False
                        _control.ProgBarStatus.Value = 0

                        _control.chkActivate.Enabled = False

                        SetFullDownloadSize = GetFullDownloadSize + _control.FileInfo.GetSetFileSize

                        _list.Add(_control)


                    End If

                End If

            Next

            'ThreadHandler starten
            Dim _t_handler As Thread

            If GetSFDLMaxThreads = 0 Then
                Throw New Exception("SFDL Datei ist defekt!")
            End If

            If _settings.GetSetMaxDownloadThreads < GetSFDLMaxThreads Then
                _t_handler = New Thread(Sub() _thread_handler.HandleThreads(_list, _settings.GetSetMaxDownloadThreads))
            Else
                _t_handler = New Thread(Sub() _thread_handler.HandleThreads(_list, GetSFDLMaxThreads))
            End If

            _t_handler.Start()

        Catch ex As Exception
            _download_running = False
            UnLockGUI_Downloading()
            MessageBox.Show("Fehler beim starten des Downloads!" & vbNewLine & "Fehler: " & ex.Message, "Fehlerhafte SFDL Datei!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try


    End Sub

    Private Sub chk_Panel_Header_CheckedChanged(sender As Object, e As EventArgs) Handles chk_Panel_Header.CheckedChanged

        If chk_Panel_Header.Checked Then

            AlleMakierenToolStripMenuItem.Checked = True

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    _control.chkActivate.Checked = True

                End If

            Next



        Else

            AlleMakierenToolStripMenuItem.Checked = False

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    _control.chkActivate.Checked = False

                End If

            Next

        End If

    End Sub

    Private Sub AlleMakierenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles AlleMakierenToolStripMenuItem.Click

        If AlleMakierenToolStripMenuItem.Checked = True Then
            chk_Panel_Header.Checked = True

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    _control.chkActivate.Checked = True

                End If

            Next

        Else

            chk_Panel_Header.Checked = False

            For Each _item In MainLayoutPanel.Controls

                If _item.GetType() Is GetType(ctrFTPClient) Then

                    Dim _control As New ctrFTPClient

                    _control = _item

                    _control.chkActivate.Checked = False

                End If

            Next

        End If
    End Sub

    Private Sub EinstellungenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles EinstellungenToolStripMenuItem.Click

        AddHandler frm_settings.SettingsUpdated, AddressOf frm_setting_settings_update_event

        frm_settings.ShowDialog()
        frm_settings.Dispose()

        RemoveHandler frm_settings.SettingsUpdated, AddressOf frm_setting_settings_update_event
    End Sub

    Private Sub ÜberSFDLNETToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ÜberSFDLNETToolStripMenuItem.Click
        AboutBox.ShowDialog()
    End Sub

#End Region

#Region "Max Speed Textbox Events"

    Private Sub txt_max_dl_speed_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txt_max_dl_speed.KeyPress

        If Not e.KeyChar = Convert.ToChar(Keys.Back) Then

            If IsNumeric(e.KeyChar.ToString) Then
                e.Handled = False
            Else
                e.Handled = True
            End If

        End If

    End Sub

    Private Sub txt_max_dl_speed_Leave(sender As Object, e As EventArgs) Handles txt_max_dl_speed.Leave

        Dim _tools As New Tools

        txt_max_dl_speed.Font = New Font(txt_max_dl_speed.Font.FontFamily, txt_max_dl_speed.Font.Size, FontStyle.Regular)

        If Not MainLayoutPanel.Controls.Count = 0 And _download_running = True Then
            RaiseEvent MaxDownloadSpeedChanged(_tools.CalculateMaxDownloadSpeed(GetSFDLMaxThreads, GetActiveThreadCount, txt_max_dl_speed.Text))
        End If

    End Sub

#End Region

#Region "MainStatusStrip Events"

    Private Sub StatusProgressBar_MouseHover(sender As Object, e As EventArgs) Handles StatusProgressBar.MouseHover
        StatusProgressBar.ToolTipText = String.Format("{0} % heruntergeladen", StatusProgressBar.Value)
    End Sub

#End Region

#Region "PostDownload"

    Sub PostDownloadAction()

        Dim _show_speedreport As Boolean = True


        If PostDownload_ShellExecute.Checked Then
            Try
                _show_speedreport = False
                Shell(_post_download_shell_cmd, AppWinStyle.NormalFocus, True, 10000)
            Catch ex As Exception
            End Try
        End If

        If PostDownload_PlaySound.Checked Then
            Try
                _show_speedreport = True
                My.Computer.Audio.Play(_post_download_sound_file, AudioPlayMode.WaitToComplete)
            Catch ex As Exception
            End Try
        End If

        If PostDownload_CloseApplication.Checked Then
            _show_speedreport = False
            _close_application = True
            CloseApp()
        End If

        If PostDownload_ShutdownPC.Checked Then
            _show_speedreport = False
            Shell("shutdown -s -t 5", AppWinStyle.Hide)
            _close_application = True
            CloseApp()
        End If

        If _show_speedreport = True And _settings.GetSetShowSpeedreportAfterDownload = True Then
            frm_speedreport.ShowDialog()
        End If


    End Sub


    Private Sub PostDownload_CloseApplication_CheckedChanged(sender As Object, e As EventArgs) Handles PostDownload_CloseApplication.CheckedChanged
        If PostDownload_CloseApplication.Checked = True Then
            PostDownload_ShutdownPC.Checked = False
        End If

    End Sub

    Private Sub PostDownload_ShutdownPC_CheckedChanged(sender As Object, e As EventArgs) Handles PostDownload_ShutdownPC.CheckedChanged
        If PostDownload_ShutdownPC.Checked Then
            PostDownload_CloseApplication.Checked = False
        End If
    End Sub

    Private Sub PostDownload_ShellExecute_CheckedChanged(sender As Object, e As EventArgs) Handles PostDownload_ShellExecute.CheckedChanged

        If PostDownload_ShellExecute.Checked = True Then

            Dim _cmd As String

            Try

                _cmd = InputBox("Befehl eingeben:", "Shell Execute")

                If String.IsNullOrEmpty(_cmd) Then
                    Throw New Exception("Befehl darf nicht leer sein!")
                End If

                _post_download_shell_cmd = _cmd

            Catch ex As Exception
                MessageBox.Show(ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                PostDownload_ShellExecute.Checked = False
            End Try

        End If

    End Sub

    Private Sub PostDownload_PlaySound_CheckedChanged(sender As Object, e As EventArgs) Handles PostDownload_PlaySound.CheckedChanged

        If PostDownload_PlaySound.Checked = True Then

            Try

                If Not OFD_SoundFile.ShowDialog = Windows.Forms.DialogResult.Cancel Then
                    _post_download_sound_file = OFD_SoundFile.FileName
                Else
                    Throw New Exception("Keine gültige Sound Datei gewählt!")
                End If

            Catch ex As Exception
                PostDownload_PlaySound.Checked = False
            End Try

        End If

    End Sub

#End Region

#Region "WhoIs Abfrage"

    Private Sub bgw_whois_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgw_whois.DoWork

        Dim _whois As New WhoisResolver
        Dim _country_code As String = String.Empty
        Dim _server As String = String.Empty

        _server = CStr(e.Argument)

        Try
            _country_code = _whois.Resolve(_server)

        Catch ex As Exception
            'fehler abfangen
        Finally
            bgw_whois.ReportProgress(0, _country_code)
        End Try

    End Sub

    Private Sub bgw_whois_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw_whois.ProgressChanged

        Dim _country_code As String = String.Empty
        Dim _flag As Image
        Dim _tools As New Tools

        Try

            _country_code = CStr(e.UserState)

            If Not String.IsNullOrEmpty(_country_code) Then

                _flag = _tools.DownloadImage("http://n1.dlcache.com/flags/" & _country_code.ToLower & ".gif")

                If Not _flag Is Nothing Then
                    ToolInfo.DropDownItems.Add("Serverstandort: " & _country_code, _flag)
                    ToolInfo.Visible = True
                End If

            End If


        Catch ex As Exception
        End Try

    End Sub

#End Region

#Region "Send To Tray"

    Private Sub frm_main_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize

        Try
            If Not _settings Is Nothing Then

                If _settings.GetSetSend2Tray = True Then

                    If Me.WindowState = FormWindowState.Minimized Then
                        Me.WindowState = FormWindowState.Minimized
                        NotifyIcon.Visible = True
                        Me.Hide()

                        NotifyIcon.BalloonTipIcon = ToolTipIcon.Info
                        NotifyIcon.BalloonTipText = "SFDL.NET wurde ins Tray minimiert!"
                        NotifyIcon.BalloonTipTitle = "SFDL.NET"
                        NotifyIcon.ShowBalloonTip(300)

                    End If

                End If

            End If

        Catch ex As Exception
        End Try

    End Sub


    Private Sub NotifyIcon_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon.MouseDoubleClick

        Try

            Me.Show()
            Me.WindowState = FormWindowState.Normal
            NotifyIcon.Visible = False

        Catch ex As Exception
        End Try

    End Sub

    Private Sub MaximierenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles MaximierenToolStripMenuItem.Click

        Try

            Me.Show()
            Me.WindowState = FormWindowState.Normal
            NotifyIcon.Visible = False

        Catch ex As Exception
        End Try

    End Sub

    Private Sub NotifyIcon_MouseClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon.MouseClick

        Dim _string_info As New StringBuilder

        Try


            If _download_running = True Then

                System.Threading.Thread.Sleep(500)

                If e.Button = Windows.Forms.MouseButtons.Left And e.Clicks = 0 Then

                    _string_info.AppendLine("")
                    _string_info.AppendLine("Geschwindigkeit: " & GetDownloadSpeed.ToString & " KB/s")
                    _string_info.AppendLine("Fortschritt: " & _tools.ConvertBytesToGB(GetSetBytesDownloaded) & " / " & _tools.ConvertBytesToGB(GetFullDownloadSize))
                    _string_info.AppendLine("ETA: " & _remaining_download_time.ToString)

                    NotifyIcon.BalloonTipIcon = ToolTipIcon.Info
                    NotifyIcon.BalloonTipTitle = "Download Info"
                    NotifyIcon.BalloonTipText = _string_info.ToString
                    NotifyIcon.ShowBalloonTip(3000)

                End If

            End If

        Catch ex As Exception
        End Try

    End Sub


#End Region

    Private Sub SFDLNETBlogToolStripMenuItem_Click_1(sender As Object, e As EventArgs) Handles SFDLNETBlogToolStripMenuItem.Click
        System.Diagnostics.Process.Start("http://www.sfdl.net")
    End Sub

    Private Sub HeaderSplitContainer_SplitterMoved(sender As Object, e As SplitterEventArgs) Handles HeaderSplitContainer.SplitterMoved

        Dim _splitter_distance As Integer

        _splitter_distance = HeaderSplitContainer.SplitterDistance

        For Each _control In Me.MainLayoutPanel.Controls

            If _control.GetType() Is GetType(ctrFTPClient) Then

                Dim _ctr_ftp As New ctrFTPClient

                _ctr_ftp = _control

                _ctr_ftp.SplitContainerMain.SplitterDistance = _splitter_distance

            End If

        Next


    End Sub

    Private Sub MainLayoutPanel_MouseEnter(sender As Object, e As EventArgs) Handles MainLayoutPanel.MouseEnter

        MainLayoutPanel.Focus()

    End Sub

#Region "Debug"

    Private Sub cmd_StartDebug_Click(sender As Object, e As EventArgs) Handles cmd_StartDebug.Click

        If _debug_enabled = False Then

            Dim _debug_file As String = IO.Path.Combine(Application.StartupPath, "debug.log")

            _debug_enabled = True

            cmd_StartDebug.Enabled = False
            cmd_stopdebug.Enabled = True

            If IO.File.Exists(_debug_file) Then

                If MessageBox.Show("Es existiert bereits eine Diagnose Datei. Überschreiben?", "Diagnose Datei vorhanden", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
                    _debug_sw = New StreamWriter(_debug_file, False, System.Text.Encoding.Default)
                Else
                    _debug_sw = New StreamWriter(_debug_file, True, System.Text.Encoding.Default)
                    _debug_sw.WriteLine("")
                    _debug_sw.WriteLine("")
                End If
            Else
                _debug_sw = New StreamWriter(_debug_file, True, System.Text.Encoding.Default)
                _debug_sw.WriteLine("")
                _debug_sw.WriteLine("")
            End If

            _debug_sw.WriteLine(" ------------------------------------- Start Debug Session - {0} -------------------------------------", Now.ToString)

            _debug_listener = New TextWriterTraceListener(_debug_sw, "Debug")

            Debug.Listeners.Add(_debug_listener)
            Debug.AutoFlush = True

            MessageBox.Show("Diagnose gestartet!", "Diagnose", MessageBoxButtons.OK, MessageBoxIcon.Information)

        End If


    End Sub

    Private Sub cmd_stopdebug_Click(sender As Object, e As EventArgs) Handles cmd_stopdebug.Click

        If _debug_enabled = True Then

            _debug_enabled = False

            cmd_StartDebug.Enabled = True
            cmd_stopdebug.Enabled = False

            Debug.AutoFlush = False
            Debug.Listeners.Remove("Debug")

            _debug_sw.WriteLine(" ------------------------------------- End Debug Session - {0} -------------------------------------", Now.ToString)


            _debug_sw.Close()
            _debug_sw.Dispose()

            MessageBox.Show("Diagnose beendet!", "Diagnose", MessageBoxButtons.OK, MessageBoxIcon.Information)


        End If

    End Sub

#End Region


End Class
